﻿using System;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Sharp.DataTransferObject;
using Sharp.Infrastructure;
using Sharp.Portal.Mvc;
using Sharp.Portal.Owin;
using Sharp.ServiceContracts;
using Sharp.Services.OAuth.Models;

// ReSharper disable Mvc.ViewNotResolved
//https://github.com/MikeWasson/LocalAccountsApp
namespace Sharp.Services.OAuth.Controllers
{
    //[Authorize]
    public class AccountController : SharpController
    {

        public AccountController()
        {
        }


        //
        // GET: /Account/Login
        [AllowAnonymous]
        public ActionResult Login(string returnUrl)
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
            ViewBag.ReturnUrl = returnUrl;

            LoginViewModel model = new LoginViewModel();

            return View(model);
        }


        //
        // POST: /Account/Login
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }
            ViewBag.ReturnUrl = returnUrl;
#if DEBUG
            if (WebServer.GetIP() != "127.0.0.1")
#endif
            {
                if (System.Web.HttpContext.Current.Session["ValidateCode"] == null)
                {
                    ModelState.AddModelError("", "验证码失效，请重新登录");
                    return View(model);
                }
                if (System.Web.HttpContext.Current.Session["ValidateCode"].ToString() != model.ValidateCode)
                {
                    ModelState.AddModelError("", "验证码错误");
                    return View(model);
                }
            }

            #region MyRegion
            //var clientId = "1234";
            //var clientSecret = "5678";
            //HttpClient httpClient = new HttpClient();
            //httpClient.BaseAddress = new Uri("http://oauth2.PlatformSharp.com");
            //httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
            //    "Basic",
            //    Convert.ToBase64String(Encoding.ASCII.GetBytes(clientId + ":" + clientSecret)));


            //var postData = new List<KeyValuePair<string, string>>();
            //postData.Add(new KeyValuePair<string, string>("grant_type", "password"));
            //postData.Add(new KeyValuePair<string, string>("UserName", model.Name));
            //postData.Add(new KeyValuePair<string, string>("Password", model.Password));
            //HttpContent content = new FormUrlEncodedContent(postData);


            //HttpResponseMessage response = await httpClient.PostAsync("/token", content);
            //response.EnsureSuccessStatusCode();
            //string accessToken = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());


            //if (!string.IsNullOrEmpty(accessToken))
            //{
            //    //var ticket = System.Security.Cryptography.DpapiDataProtector.Unprotect(accessToken);
            //    //var id = new ClaimsIdentity(ticket.Identity.Claims, DefaultAuthenticationTypes.ApplicationCookie);
            //    //AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = true }, id);

            //    //return RedirectToLocal(returnUrl);
            //    var indentity = AuthenticationManager.GetExternalIdentity(DefaultAuthenticationTypes.ExternalCookie);
            //    AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = true }, indentity);

            //    return RedirectToLocal(returnUrl);
            //}

            //ModelState.AddModelError("Error", "Invalid Authentication");
            #endregion

            var result = await SignInManager.PasswordSignInAsync(model.Name, model.Password, model.RememberMe, shouldLockout: false);
            

            switch (result)
            {
                case SignInStatus.Success:
                    using (var proxy = new ServiceProxy<IUserService>())
                    {
                        var res = proxy.Channel.TryLogin(new UserDTO()
                        {
                            UserName = model.Name,
                            Password = model.Password,
                            LastLogonIp = WebServer.GetIP()
                        });
                        ContactContext.Current.UserId = res.Data.Id;
                        ContactContext.Current.UserName = res.Data.UserName;

                        SharpUserManager.Current = new SharpUser(res.Data);
                    }
                    

                    return Redirect("~/");
                case SignInStatus.LockedOut:
                    ModelState.AddModelError("", "账号已被锁定。");
                    return View(model);
                case SignInStatus.RequiresVerification:
                    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "无效的登录尝试。");
                    return View(model);
            } 
        }

        public ActionResult LogOff()
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
            return RedirectToAction("Login");
        }

        #region 验证码

        [AllowAnonymous]
        public ActionResult GetValidateCode()
        {
            ValidateCode vCode = new ValidateCode();
            string code = vCode.CreateValidateCode(4);
            Session["ValidateCode"] = code;
            byte[] bytes = vCode.CreateValidateGraphic(code);
            return File(bytes, @"image/jpeg");
        }

        #endregion

        /// <summary>
        /// 忘记密码
        /// </summary>
        /// <returns></returns>
        public ActionResult ForgotPassword()
        {
            var model = new ForgotPasswordViewModel();
            return View("ForgotPassword", model);
        }

        /// <summary>
        /// 取回密码
        /// </summary>
        /// <param name="vm"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult ForgotPassword(ForgotPasswordViewModel vm)
        {
            using (var proxy = new ServiceProxy<IUserService>())
            {
                var dto = vm.To<ForgotPasswordDTO>();
                dto.Email = vm.Email;
                dto.CallBackUrl = HttpContext.Request.Url.Authority;

                var res = proxy.Channel.ForgotPassword(dto);
                vm.Message = res.Message;

                return View(vm);
            }
        }

        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="token">防伪识别码</param>
        /// <returns></returns>
        [HttpGet]
        public ActionResult ResetPassword(Guid token)
        {
            var vm = new ResetPasswordViewModel
            {
                Token = token.ToString()
            };
            return View(vm);
        }

        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="vm"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult ResetPassword(ResetPasswordViewModel vm)
        {
            if (vm == null)
            {
                ModelState.AddModelError("", "提交数据出错。");
                return View(new ResetPasswordViewModel());
            }
            Result res;
            using (var proxy = new ServiceProxy<IUserService>())
            {
                res = proxy.Channel.ResetPassword(vm.To<ResetPasswordDTO>());
            }

            if (res.Err.Length > 0)
                ModelState.AddModelError("", res.Err);

            return View(vm);
        }

        

        public ActionResult ChangePassword()
        {
            var model = new ChangePassword();
            return View("ChangePassword", model);
        }

        [HttpPost]
        public ActionResult ChangePassword(ChangePassword vm)
        {
            if (vm == null)
            {
                return this.JsonNet(new Result { Err = "提交数据出错。" });
            }
            if (vm.PasswordNew != vm.PasswordNewS)
            {
                return this.JsonNet(new Result { Err = "两次输入新密码不一致，请重新输入！" });

            }
            using (var proxy = new ServiceProxy<IUserService>())
            {

                var res = proxy.Channel.ChangePassword(SharpUserManager.Current.UserName, vm.Password, vm.PasswordNew);

                return this.JsonNet(res);
            }
        }

        #region 帮助程序
        private SharpSignInManager _signInManager;
        private SharpUserManager _userManager;
        // 用于在添加外部登录名时提供 XSRF 保护
        private const string XsrfKey = "XsrfId";
        public SharpSignInManager SignInManager
        {
            get => _signInManager ?? HttpContext.GetOwinContext().Get<SharpSignInManager>();
            set => _signInManager = value;
        }

        public SharpUserManager UserManager
        {
            get => _userManager ?? HttpContext.GetOwinContext().GetUserManager<SharpUserManager>();
            set => _userManager = value;
        }
        private IAuthenticationManager AuthenticationManager => HttpContext.GetOwinContext().Authentication;

        private void AddErrors(IdentityResult result)
        {
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError("", error);
            }
        }

        internal class ChallengeResult : HttpUnauthorizedResult
        {
            public ChallengeResult(string provider, string redirectUri)
                : this(provider, redirectUri, null)
            {
            }

            public ChallengeResult(string provider, string redirectUri, string userId)
            {
                LoginProvider = provider;
                RedirectUri = redirectUri;
                UserId = userId;
            }

            public string LoginProvider { get; set; }
            public string RedirectUri { get; set; }
            public string UserId { get; set; }

            public override void ExecuteResult(ControllerContext context)
            {
                var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
                if (UserId != null)
                {
                    properties.Dictionary[XsrfKey] = UserId;
                }
                context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
            }
        }
        #endregion

        #region 外部登录
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult ExternalLogin(string provider, string returnUrl)
        {
            // Request a redirect to the external login provider
            return new ChallengeResult(
                provider, 
                Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }), null);
        }

        //
        // GET: /Account/ExternalLoginCallback
        [AllowAnonymous]
        public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
        {
            var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
            if (loginInfo == null)
            {
                return RedirectToAction("Login");
            }

            // Sign in the user with this external login provider if the user already has a login
            var user = await UserManager.FindAsync(loginInfo.Login);
            if (user != null)
            {
                await SignInAsync(user, isPersistent: false);
                return RedirectToLocal(returnUrl);
            }
            else
            {
                // If the user does not have an account, then prompt the user to create an account
                ViewBag.ReturnUrl = returnUrl;
                ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
                return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName });
            }
        }

        private async Task SignInAsync(SharpUser user, bool isPersistent)
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
            var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
        }
        private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        #endregion


    }
}